/**
 * Node.js的单个实例在单个线程中运行。
 * 为了利用多核系统，用户有时会想要启动Node.js进程的集群来处理负载
 * 集群模块可以轻松创建共享服务器端口的子进程
 */

// cluster模块的主要使用场景是网络，但是也可以用于工作进程的其他使用场景
const cluster = require("cluster");
const http = require("http");

/* cluster.isMaster是cluster.isPrimary（已弃用）的别称
如果进程是主进程，则为真 */
if (cluster.isMaster) {
    // 跟踪http请求
    let numReqs = 0;
    setInterval(() => {
        console.log(`numReqs=${numReqs}`);
    }, 1000);

    // 计数请求
    // 在主进程中记录工作进程接收到的HTTP请求数
    function messageHandler(msg) {
        // cmd是服务器中进程所传的参数
        if (msg.cmd && msg.cmd === "notifyRequest") {
            numReqs += 1;
        }
    }

    // 启动工作进程并监听包含notifyRequest的消息

    // os模块提供了与操作系统相关的使用方法和属性
    // 使用require('os')来使用
    // os.cpus()返回包含有关每个逻辑CPU内核的信息的对象数组
    const numCPUs = require("os").cpus().length;
    console.log(numCPUs);

    for (let i = 0; i < numCPUs; i++) {
        // cluster工作进程使用child_process.fork()方法衍生，
        // 可以通过IPC与父进程通信并且来回传递服务器句柄
        cluster.fork();
    }

    for (const id in cluster.workers) {
        // cluster.workers[id],存储活动工作进程对象的哈希，以id字段为键
        // 使循环遍历所有工作进程变得容易
        /* 在工作进程断开连接并退出后，工作进程会从 cluster.workers 中删除。
         这两个事件之间的顺序无法预先确定。 
         但是，可以保证从 cluster.workers 列表中的删除发生在最后一个 'disconnect' 或 'exit' 事件触发之前。 */
        cluster.workers[id].on("messageHandler");
    }
} else {
    // 工作进程具有http服务器
    http.Server((req, res) => {
        res.writeHead(200);
        res.end("hello world\n");

        // 通知主进程关于请求
        process.send({ cmd: `notifyRequest` });
    }).listen(8000);
}
